#include "stdio.h"
#include "stdlib.h"
#include "string.h"

typedef struct queue{
    char *name;
    int queueLen;
    int msgLen;
    int capacity;
    int queueAvailable;
    int queueUsed;
    void *queuePoolPtr;
    void *queueRead;
    void *queueWrite;
} Queue_t;

typedef Queue_t* QueueHandle_t;

QueueHandle_t createQueue(char *name, int queueLen, int msgLen){
    QueueHandle_t queuePtr = malloc(sizeof(Queue_t));
    if(!queuePtr){
        printf("malloc failed.\n");
    }
    queuePtr->capacity = queueLen * msgLen;
    queuePtr->queuePoolPtr = malloc(queuePtr->capacity);
    if(!queuePtr->queuePoolPtr){
        printf("queue create failed, memery alloc failed!\n");
        return NULL;
    }
    queuePtr->queueRead = queuePtr->queuePoolPtr;
    queuePtr->queueWrite = queuePtr->queuePoolPtr;
    queuePtr->name = name;
    queuePtr->queueLen = queueLen;
    queuePtr->msgLen = msgLen;
    queuePtr->queueAvailable = queueLen;
    queuePtr->queueUsed = 0;

    return queuePtr;
}

int sendQueue(QueueHandle_t handle, void *msg){
    if(handle->queueAvailable > 0){
        memcpy(handle->queueWrite, msg, handle->msgLen);
        if(handle->queueWrite == (handle->queuePoolPtr + handle->capacity)){
            handle->queueWrite = handle->queuePoolPtr;
        }else{
            handle->queueWrite = handle->queueWrite + handle->msgLen;
        }    
        handle->queueAvailable--;
        handle->queueUsed++;
    }else{
        printf("queue is full.\n");
        return 0;
    }
    return handle->msgLen;
}

int receiveQueue(QueueHandle_t handle, void *msg){
    if(msg == NULL){
        printf("msg is null.\n");
        return 0;
    }
    if(handle == NULL){
        printf("handle is null.\n");
        return 0;
    }
    if(handle->queueUsed > 0){
        memcpy(msg, handle->queueRead, handle->msgLen);
        if(handle->queueRead == (handle->queuePoolPtr + handle->capacity)){
            handle->queueRead = handle->queuePoolPtr;
        }else{
            handle->queueRead = handle->queueRead + handle->msgLen;
        } 
        handle->queueAvailable++;
        handle->queueUsed--;
    }else{
        printf("queue is empty.\n");
        return 0;
    }    

    return handle->msgLen;
}

int main(void){
    int msg = 1;
    int recMsg;
    QueueHandle_t mq = createQueue("hellomq", 6, sizeof(int));
    if(mq){
        sendQueue(mq, &msg);
        msg++;
        sendQueue(mq, &msg);
        msg++;
        sendQueue(mq, &msg);
        msg++;
        sendQueue(mq, &msg);
        msg++;
        sendQueue(mq, &msg);
        msg++;
        sendQueue(mq, &msg);
        receiveQueue(mq, &recMsg);printf("%d\n", recMsg);
        receiveQueue(mq, &recMsg);printf("%d\n", recMsg);
        receiveQueue(mq, &recMsg);printf("%d\n", recMsg);
        receiveQueue(mq, &recMsg);printf("%d\n", recMsg);
        receiveQueue(mq, &recMsg);printf("%d\n", recMsg);
        receiveQueue(mq, &recMsg);printf("%d\n", recMsg);
        sendQueue(mq, &msg);
        msg++;
        sendQueue(mq, &msg);
        msg++;
        sendQueue(mq, &msg);
        msg++;
        sendQueue(mq, &msg);
        msg++;
        sendQueue(mq, &msg);
        msg++;
        sendQueue(mq, &msg);
        receiveQueue(mq, &recMsg);printf("%d\n", recMsg);
        receiveQueue(mq, &recMsg);printf("%d\n", recMsg);
        receiveQueue(mq, &recMsg);printf("%d\n", recMsg);
        receiveQueue(mq, &recMsg);printf("%d\n", recMsg);
        receiveQueue(mq, &recMsg);printf("%d\n", recMsg);
        receiveQueue(mq, &recMsg);printf("%d\n", recMsg);
        sendQueue(mq, &msg);
        msg++;
        sendQueue(mq, &msg);
        msg++;
        sendQueue(mq, &msg);
        msg++;
        sendQueue(mq, &msg);
        msg++;
        sendQueue(mq, &msg);
        msg++;
        sendQueue(mq, &msg);
        receiveQueue(mq, &recMsg);printf("%d\n", recMsg);
        receiveQueue(mq, &recMsg);printf("%d\n", recMsg);
        receiveQueue(mq, &recMsg);printf("%d\n", recMsg);
        receiveQueue(mq, &recMsg);printf("%d\n", recMsg);
        receiveQueue(mq, &recMsg);printf("%d\n", recMsg);
        receiveQueue(mq, &recMsg);printf("%d\n", recMsg);
        
    }

}